Complete binary tree inserter

Time: ctor:O(N), insert:O(1), get_root:O(1); Space: O(N); medium

A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.

Write a data structure CBTInserter that is initialized with a complete binary tree and supports the following operations:

  • CBTInserter(TreeNode root) initializes the data structure on a given tree with head node root;

  • CBTInserter.insert(int v) will insert a TreeNode into the tree with value node.val = v so that the tree remains complete, and returns the value of the parent of the inserted TreeNode;

  • CBTInserter.get_root() will return the head node of the tree.

Example 1:

Input/Output:

  • s = CBTInserter(1) -> None

  • s.insert(2) -> 1

  • s.get_root -> [1,2]

Example 2:

Input/Output:

  • s = CBTInserter([1,2,3,4,5,6]) -> None

  • s.insert(7) -> 3

  • s.insert(8) -> 4

  • s.get_root() -> [1,2,3,4,5,6,7,8]

Notes:

  • The initial given tree is complete and contains between 1 and 1000 nodes.

  • CBTInserter.insert is called at most 10000 times per test case.

  • Every value of a given or inserted node is between 0 and 5000.

[19]:
class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

Auxiliary Tools¶

[20]:
from graphviz import Graph

class TreeTasks(object):
    def visualize_tree(self, tree):
        def add_nodes_edges(tree, dot=None):
            # Create Graph (not Digraph) object
            if dot is None:
                dot = Graph()
                dot.node(name=str(tree), label=str(tree.val))
            # Add nodes
            if tree.left:
                dot.node(name=str(tree.left), label="."+str(tree.left.val))
                dot.edge(str(tree), str(tree.left))
                dot = add_nodes_edges(tree.left, dot=dot)
            if tree.right:
                dot.node(name=str(tree.right), label=str(tree.right.val)+".")
                dot.edge(str(tree), str(tree.right))
                dot = add_nodes_edges(tree.right, dot=dot)
            return dot
        # Add nodes recursively and create a list of edges
        dot = add_nodes_edges(tree)
        # Visualize the graph
        display(dot)
        return dot
[21]:
class CBTInserter(object):

    def __init__(self, root):
        """
        :type root: TreeNode
        """
        self.__tree = [root]
        for i in self.__tree:
            if i.left:
                self.__tree.append(i.left)
            if i.right:
                self.__tree.append(i.right)

    def insert(self, v):
        """
        :type v: int
        :rtype: int
        """
        n = len(self.__tree)
        self.__tree.append(TreeNode(v))
        if n % 2:
            self.__tree[(n-1)//2].left = self.__tree[-1]
        else:
            self.__tree[(n-1)//2].right = self.__tree[-1]
        return self.__tree[(n-1)//2].val

    def get_root(self):
        """
        :rtype: TreeNode
        """
        return self.__tree[0]
[22]:
root = TreeNode(1)
c = CBTInserter(root)

assert c.insert(2) == 1
tree = c.get_root()
t = TreeTasks()
dot = t.visualize_tree(tree)
assert tree.val == 1
assert tree.left.val == 2
../../_images/topics_tree_0919_complete_binary_tree_inserter_[VAR,O(N),med]_5_0.svg
[23]:
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
c = CBTInserter(root)
assert c.insert(7) == 3
assert c.insert(8) == 4
tree = c.get_root()
t = TreeTasks()
dot = t.visualize_tree(tree)
../../_images/topics_tree_0919_complete_binary_tree_inserter_[VAR,O(N),med]_6_0.svg